package com.evolved.automata.experimental;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import com.evolved.automata.*;
import java.util.*;


public class ProbabilisticGenome implements Serializer, Genome {
	
	BehaviorDistribution j_InnateNegativeResponses;
	BehaviorDistribution j_InnatePositiveResponses;
	int[] j_AdditionalInnateParameters;
	
	private String j_UniqueName;
	private SerializerAdapter j_SerializerHelper;
	
	// Parameters related to Serialization
	private enum LoadState
	{
		LOADING_NEGATIVE_RESPONSES,
		LOADING_POSITIVE_RESPONSES,
		LOADING_ADDITIONAL_PARAMETERS,
		EXIT
	}
	
	private enum SaveState
	{
		SAVING_NEGATIVE_RESPONSES,
		SAVING_POSITIVE_RESPONSES,
		SAVING_ADDITIONAL_PARAMETERS,
		EXIT
	}
	
	LoadState j_CurrentState;
	int j_AdditionalParameterLength;
	int j_AdditionalParameterIndex;
	
	
	private int j_Fitness=0;
	public ProbabilisticGenome()
	{
		j_SerializerHelper= new SerializerAdapter(this);
		j_CurrentState=LoadState.LOADING_NEGATIVE_RESPONSES;
	}
	
	public ProbabilisticGenome(int[] stateVectorRadii, double initialWeight, int totalActions, int allocationBuffer)
	{
		j_SerializerHelper= new SerializerAdapter(this);
		j_CurrentState=LoadState.LOADING_NEGATIVE_RESPONSES;
		
		j_InnateNegativeResponses = new BehaviorDistribution(stateVectorRadii,initialWeight,totalActions,allocationBuffer);
		j_InnatePositiveResponses = new BehaviorDistribution(stateVectorRadii,initialWeight,totalActions,allocationBuffer);
	}
	
	public ProbabilisticGenome(int[] stateVectorRadii, LinkedList<WeightedValue<Integer>> actions, int allocationBuffer)
	{
		j_SerializerHelper= new SerializerAdapter(this);
		j_CurrentState=LoadState.LOADING_NEGATIVE_RESPONSES;
		
		j_InnateNegativeResponses = new BehaviorDistribution(stateVectorRadii,actions,allocationBuffer);
		j_InnatePositiveResponses = new BehaviorDistribution(stateVectorRadii,actions,allocationBuffer);
	}
	
	
	public int GetFitness()
	{
		return j_Fitness;
	}
	
	public void SetFitness(int fitness)
	{
		j_Fitness=fitness;
	}
	
	
	public BehaviorDistribution GetPositiveDistribution()
	{
		return j_InnatePositiveResponses;
	}
	
	public BehaviorDistribution GetNegativeDistribution()
	{
		return j_InnateNegativeResponses;
	}
	
	public int[] GetAdditionalParameters()
	{
		return j_AdditionalInnateParameters;
	}
	
	public void SetInnatePositiveDistrib(BehaviorDistribution distrib)
	{
		j_InnatePositiveResponses=distrib;
	}
	
	public void SetInnateNegativeDistrib(BehaviorDistribution distrib)
	{
		j_InnateNegativeResponses=distrib;
	}
	
	public void SetAdditionalParameters(int[] parameters)
	{
		j_AdditionalInnateParameters=parameters;
	}
	
	public Object clone()
	{
		
		ProbabilisticGenome g = new ProbabilisticGenome();
		if (j_AdditionalInnateParameters!=null)
			g.SetAdditionalParameters((int[])j_AdditionalInnateParameters.clone());
		if (j_InnateNegativeResponses!=null)
			g.SetInnateNegativeDistrib((BehaviorDistribution)j_InnateNegativeResponses.clone());
		if (j_InnatePositiveResponses!=null)
			g.SetInnatePositiveDistrib((BehaviorDistribution)j_InnatePositiveResponses.clone());
		return g;
	}
	
	// Serializer methods
	public String GetTypeName()
	{
		return "ProbabilisticGenome";
	}
	
	public void PrepareSerialization()
	{
		j_CurrentState=LoadState.LOADING_NEGATIVE_RESPONSES;
	}
	
	public void SetName(String uniqueName)
	{
		j_UniqueName=uniqueName;
		j_SerializerHelper.SetUniqueName(uniqueName);
	}
	
	public void Load(BufferedReader reader)
	{
		j_SerializerHelper.Load(reader);
	}
	
	
	public void Load(String fileFullName)
	{
		j_SerializerHelper.Load(fileFullName);
		
	}
	

	
	public void Save(String fileFullName)
	{
		j_SerializerHelper.Save(fileFullName);
	}
	
	
	public  void Save(BufferedWriter writer)
	{
		j_SerializerHelper.Save(writer);
	}
	
	
	
	public void SaveData(BufferedWriter writer)
	{
		SaveState currentSaveState = SaveState.SAVING_NEGATIVE_RESPONSES;
		String data;
		boolean first=true;
		
		try
		{
			while (currentSaveState!=SaveState.EXIT)
			{
				switch (currentSaveState)
				{
					case SAVING_NEGATIVE_RESPONSES:
						if (j_InnateNegativeResponses!=null)
						{
							j_InnateNegativeResponses.SetName(GetDataName(j_InnateNegativeResponses.GetTypeName(),"neg"));
							j_InnateNegativeResponses.Save(writer);
						}
						else
						{
							writer.write(":");
							writer.newLine();
						}
						currentSaveState=SaveState.SAVING_POSITIVE_RESPONSES;
						break;
					case SAVING_POSITIVE_RESPONSES:
						// Write each dimension
						if (j_InnatePositiveResponses!=null)
						{
							j_InnatePositiveResponses.SetName(GetDataName(j_InnatePositiveResponses.GetTypeName(),"pos"));
							j_InnatePositiveResponses.Save(writer);
						}
						else
						{
							writer.write(":");
							writer.newLine();
						}
						currentSaveState=SaveState.SAVING_ADDITIONAL_PARAMETERS;
						break;
					case SAVING_ADDITIONAL_PARAMETERS:
						if (j_AdditionalInnateParameters!=null)
						{
							StaticTools.WriteArray(writer, j_AdditionalInnateParameters);
						}
						else
						{
							writer.write(":");
							writer.newLine();
						}
						currentSaveState=SaveState.EXIT;
						break;
					
				}
				
			}
		}
		catch (Exception e)
		{
			java.io.StringWriter traceText = new java.io.StringWriter();
			java.io.PrintWriter pWriter = new java.io.PrintWriter(traceText,true);
			e.printStackTrace(pWriter);
			pWriter.close();
			throw new RuntimeException(traceText.toString());
		}


	}
	
	private String GetDataName(String typeId, String instanceId)
	{
		return String.format("%1$s.%2$s.%3$s", j_UniqueName,typeId,instanceId);
	}
	
	public void AddData(String dataLine)
	{
		switch (j_CurrentState)
		{
			case LOADING_NEGATIVE_RESPONSES:
				j_CurrentState=LoadState.LOADING_POSITIVE_RESPONSES;
				break;
			case LOADING_POSITIVE_RESPONSES:
				j_CurrentState=LoadState.LOADING_ADDITIONAL_PARAMETERS;
				break;
			case LOADING_ADDITIONAL_PARAMETERS:
				if (dataLine.length()>0)
				{
					String[] data=dataLine.split(",");
					j_AdditionalInnateParameters = new int[data.length];
					for (int i=0;i<data.length;i++)
					{
						j_AdditionalInnateParameters[i]=Integer.parseInt(data[i]);
					}
				}
				j_CurrentState=LoadState.EXIT;
				break;
			
		}
	}
	
	
	public void AddData(Serializer inner, String instanceId)
	{
		switch (j_CurrentState)
		{
			case LOADING_NEGATIVE_RESPONSES:
				j_InnateNegativeResponses=(BehaviorDistribution)inner;
				j_CurrentState=LoadState.LOADING_POSITIVE_RESPONSES;
				break;
			case LOADING_POSITIVE_RESPONSES:
				j_InnatePositiveResponses=(BehaviorDistribution)inner;
				j_CurrentState=LoadState.LOADING_ADDITIONAL_PARAMETERS;
				break;
			
		}
	}
	// End Serializer methods
}

